10.2 Cookies 池的搭建¶
1. 本节目标¶
我们以天眼查和企查查为例来实现一个 Cookies 池的搭建过程。Cookies 池中保存了该网站的账号和登录后的 Cookies 信息,并且 Cookies 池还需要定时检测每个 Cookies 的有效性,如果某 Cookies 无效,那就删除该 Cookies 并模拟登录生成新的 Cookies。同时 Cookies 池还需要一个非常重要的接口,即获取随机 Cookies 的接口,Cookies 运行后,我们只需请求该接口,即可随机获得一个 Cookies 并用其爬取。
由此可见,Cookies 池需要有自动生成 Cookies、定时检测 Cookies、提供随机 Cookies
等几大核心功能。
2. 准备工作¶
搭建之前肯定需要一些微博的账号。需要安装好 Redis 数据库并使其正常运行。需要安装 Python 的 redis-py、requests、Selelnium 和 Flask 库。另外,还需要安装 Chrome 浏览器并配置好 ChromeDriver。
3. Cookies 池架构¶
Cookies 的架构和代理池类似,同样是 4 个核心模块,如图 10-10 所示。
图 10-10 Cookies 池架构
Cookies 池架构的基本模块分为 4 块:存储模块、生成模块、检测模块和接口模块。每个模块的功能如下。
- 存储模块负责存储每个账号的用户名密码以及每个账号对应的 Cookies 信息,同时还需要提供一些方法来实现方便的存取操作。
- 生成模块负责生成新的 Cookies。此模块会从存储模块逐个拿取账号的用户名和密码,然后模拟登录目标页面,判断登录成功,就将 Cookies 返回并交给存储模块存储。
- 检测模块需要定时检测数据库中的 Cookies。在这里我们需要设置一个检测链接,不同的站点检测链接不同,检测模块会逐个拿取账号对应的 Cookies 去请求链接,如果返回的状态是有效的,那么此 Cookies 没有失效,否则 Cookies 失效并移除。接下来等待生成模块重新生成即可。
- 接口模块需要用 API 来提供对外服务的接口。由于可用的 Cookies 可能有多个,我们可以随机返回 Cookies 的接口,这样保证每个 Cookies 都有可能被取到。Cookies 越多,每个 Cookies 被取到的概率就会越小,从而减少被封号的风险。
以上设计 Cookies 池的基本思路和前面讲的代理池有相似之处。接下来我们设计整体的架构,然后用代码实现该 Cookies 池。
4. Cookies 池的实现¶
首先分别了解各个模块的实现过程。
存储模块¶
其实,需要存储的内容无非就是账号信息和 Cookies 信息。
账号由用户名和密码两部分组成,我们可以存成用户名和密码的映射
。
Cookies 可以存成 JSON 字符串,但是我们后面得需要根据账号来生成 Cookies。
生成的时候我们需要知道哪些账号已经生成了 Cookies,哪些没有生成,所以需要同时保存该 Cookies 对应的用户名信息,其实也是用户名和 Cookies 的映射
。
这里就是两组映射,我们自然而然想到 Redis 的 Hash,于是就建立两个 Hash,结构分别如图 10-11 和图 10-12 所示。
图 10-11 用户名密码 Hash 结构
图 10-12 用户名 Cookies Hash 结构
Hash 的 Key 就是账号,Value 对应着密码或者 Cookies。
另外需要注意,由于 Cookies 池需要做到可扩展,存储的账号和 Cookies 不一定单单只有本例中的网站,其他站点同样可以对接此 Cookies 池,所以这里 Hash 的名称可以做二级分类
,例如存账号的 Hash 名称可以为 accounts:tianyancha,Cookies 的 Hash 名称可以为 cookies:tianyancha。
如要扩展企查查的 Cookies 池,我们就可以使用 accounts:qichacha 和 cookies:qichacha,这样比较方便。
好,接下来我们就创建一个存储模块类,用以提供一些 Hash 的基本操作,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # -*- coding: utf-8 -*- """ Created on Wed Sep 9 16:13:20 2020 @author: Devil """ import random import redis from cookiespool.config import * # 存储模块 class RedisClient(object): """ 存储模块类 这里我们新建了一个 RedisClient 类, 初始化__init__() 方法有两个关键参数 type 和 website, 分别代表类型和站点名称,它们就是用来拼接 Hash 名称的两个字段。 如果这是存储账户的 Hash,那么此处的 type 为 accounts、website 为 weibo, 如果是存储 Cookies 的 Hash,那么此处的 type 为 cookies、website 为 weibo。 """ def __init__(self, type, website, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD): """ 初始化Redis连接 :param host: 地址 :param port: 端口 :param password: 密码 """ self.db = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True) ##创建StrictRedis对象,与redis服务器建⽴连接 self.type = type #type是干啥的 self.website = website #website是网站名 def name(self): """ 获取Hash的名称 :return: Hash名称 """ return "{type}:{website}".format(type=self.type, website=self.website) def set(self, username, value): """ 设置键值对(需要传递hash的名字,没有的话会直接创建的) :param username: 用户名 :param value: 密码或Cookies :return: """ return self.db.hset(self.name(), username, value) def get(self, username): """ 根据键名获取键值 :param username: 用户名 :return: """ return self.db.hget(self.name(), username) def delete(self, username): """ 根据键名删除键值对 :param username: 用户名 :return: 删除结果 """ return self.db.hdel(self.name(), username) def count(self): """ 获取数目 :return: 数目 """ return self.db.hlen(self.name()) def random(self): """ 随机得到键值,用于随机Cookies获取 :return: 随机Cookies """ return random.choice(self.db.hvals(self.name())) def usernames(self): """ 获取所有账户信息 :return: 所有用户名 """ return self.db.hkeys(self.name()) def all(self): """ 获取所有键值对 :return: 用户名和密码或Cookies的映射表 """ return self.db.hgetall(self.name()) if __name__ == '__main__': conn = RedisClient('accounts', 'weibo') result = conn.set('hell2o', 'sss3s') #1是成功存储,0是失败 # result = conn.get('hell2o') print(result) |
配置文件中存储了redis数据库的信息
1 2 3 4 5 6 7 8 | # Redis数据库地址 REDIS_HOST = 'localhost' # Redis端口 REDIS_PORT = 6379 # Redis密码,如无填None REDIS_PASSWORD = 'Hua@123123' |
生成模块¶
生成模块负责获取各个账号信息并模拟登录,随后生成 Cookies 并保存。我们首先获取两个 Hash 的信息,看看账户的 Hash 比 Cookies 的 Hash 多了哪些还没有生成 Cookies 的账号,然后将剩余的账号遍历,再去生成 Cookies 即可。
这里主要逻辑就是找出那些还没有对应 Cookies 的账号,然后再逐个获取 Cookies,代码如下:
1 2 3 4 5 | for username in accounts_usernames: if not username in cookies_usernames: password = self.accounts_db.get(username) print(' 正在生成 Cookies', ' 账号 ', username, ' 密码 ', password) result = self.new_cookies(username, password) |
整个的生成器模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | # import json from selenium import webdriver from selenium.webdriver import DesiredCapabilities from cookiespool.config import * from cookiespool.db import RedisClient from login.tianyancha.cookies import TianYanChaCookies #导入天眼查模拟登陆模块 from login.qichacha.cookies import QiChaChaCookies class CookiesGenerator(object): def __init__(self, website='default'): """ 父类, 初始化一些对象 :param website: 名称 :param browser: 浏览器, 若不使用浏览器则可设置为 None """ self.website = website self.cookies_db = RedisClient('cookies', self.website) self.accounts_db = RedisClient('accounts', self.website) def new_cookies(self, username, password): """ 新生成Cookies,子类需要重写 :param username: 用户名 :param password: 密码 :return: """ raise NotImplementedError def run(self): """ 运行, 得到所有账户, 然后顺次模拟登录 :return: """ accounts_usernames = self.accounts_db.usernames() # 账户密码字典 cookies_usernames = self.cookies_db.usernames() # 账户cookies字典 for username in accounts_usernames: # 从账户密码中遍历用户,查看另一个字典中是不是已经有了相应的键值对 if not username in cookies_usernames: # 没有的话 password = self.accounts_db.get(username) # 获取该账户的密码 print('正在生成%s_Cookies' % self.website, '账号', username, '密码', password) # 打印提示 result = self.new_cookies(username, password) # 调用生成cookies # 成功获取 if result: # cookies = self.process_cookies(result) #将字符串格式的cookies转换成字典进行存储 cookies = result print('成功获取到%s_Cookies' % self.website, cookies) if self.cookies_db.set(username, json.dumps(cookies)): # 返回的cookies已经保存成字典的形式,存储到redis中需要转换成json格式 print('成功保存%s_Cookies' % self.website) else: print(result.get('content')) else: print('%s_所有账号都已经成功获取Cookies'% self.website) class TianYanChaCookiesGenerator(CookiesGenerator): def __init__(self, website='tianyancha'): """ 初始化操作 :param website: 站点名称 :param browser: 使用的浏览器 """ CookiesGenerator.__init__(self, website) # 父类初始化 self.website = website def new_cookies(self, username, password): # 输入账户和密码生成cookies """ 调用天眼查的cookies生成方法来生成Cookies :param username: 用户名 :param password: 密码 :return: 用户名和Cookies """ return TianYanChaCookies(username, password).main() # 这里调用的是导入的cookie生成函数 class QiChaChaCookiesGenerator(CookiesGenerator): def __init__(self, website='qichacha'): """ 初始化操作 :param website: 站点名称 :param browser: 使用的浏览器 """ CookiesGenerator.__init__(self, website) # 父类初始化 self.website = website def new_cookies(self, username, password): # 输入账户和密码生成cookies """ 生成Cookies :param username: 用户名 :param password: 密码 :return: 用户名和Cookies """ return QiChaChaCookies(username, password).main() # 这里调用的是导入的cookie生成函数 if __name__ == '__main__': generator = QiChaChaCookiesGenerator() generator.run() |
这里对接的是天眼查和企查查,返回结果的类型是字典,这里有没有返回结果其实无所谓,后面检测模块发现cookies无效后续会重新生成.
如果要扩展其他站点,只需要实现 new_cookies() 方法即可,然后按此处理规则返回对应的模拟登录结果.
代码运行之后就会遍历一次尚未生成 Cookies 的账号,模拟登录生成新的 Cookies。
天眼查模拟登陆代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | from selenium import webdriver import time from PIL import Image import random import numpy as np import os from PIL import ImageChops, PngImagePlugin # TEMPLATES_FOLDER = dirname(abspath(__file__)) + '/templates/' class TianYanChaCookies(): def __init__(self, username, password): self.username = username self.password = password def get_gap(self, image1, image2): """ 获取缺口偏移量 :param image1: 不带缺口图片 :param image2: 带缺口图片 :return: """ # 将图片修改为RGB模式 image1 = image1.convert("RGB") image2 = image2.convert("RGB") # 计算差值 diff = ImageChops.difference(image1, image2) # 灰度图 diff = diff.convert("L") table = [] for i in range(256): if i < 50: table.append(0) else: table.append(1) # 二值化 diff = diff.point(table, '1') left = 58 # 这里做了优化为减少误差 纵坐标的像素点大于5时才认为是找到 # 防止缺口有凸起时有误差 for w in range(left, diff.size[0]): lis = [] for h in range(diff.size[1]): if diff.load()[w, h] == 1: lis.append(w) if len(lis) > 5: left = w return left def is_pixel_equal(self, image1, image2, x, y): """ 判断两个像素是否相同 :param image1: 图片1 :param image2: 图片2 :param x: 位置x :param y: 位置y :return: 像素是否相同 """ # 取两个图片的像素点 pixel1 = image1.load()[x, y] pixel2 = image2.load()[x, y] threshold = 60 if abs(pixel1[0] - pixel2[0]) < threshold and abs(pixel1[1] - pixel2[1]) < threshold and abs( pixel1[2] - pixel2[2]) < threshold: return True else: return False # def ease_out_quad(self, x): return 1 - (1 - x) * (1 - x) def ease_out_quart(self, x): return 1 - pow(1 - x, 4) def ease_out_expo(self, x): if x == 1: return 1 else: return 1 - pow(2, -10 * x) def get_tracks_2(self, distance, seconds, ease_func): """ 根据轨迹离散分布生成的数学 生成 # 参考文档 https://www.jianshu.com/p/3f968958af5a 成功率很高 90% 往上 :param distance: 缺口位置 :param seconds: 时间 :param ease_func: 生成函数 :return: 轨迹数组 """ distance += 20 tracks = [0] offsets = [0] for t in np.arange(0.0, seconds, 0.1): ease = ease_func offset = round(ease(t / seconds) * distance) tracks.append(offset - offsets[-1]) offsets.append(offset) tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1]) # print(tracks) return tracks def slide_block(self, image1, image2, circle_button, driver, variable): ''' 模拟操作滑块进行滑动,成功率不高,所以加上了函数后,进行循环操作 ''' distance = int(self.get_gap(image1, image2)) - 7 + variable # print("距离:%s" % distance) track_list =self.get_tracks_2(distance, 5, self.ease_out_expo) # print("轨迹参数:", track_list) time.sleep(1) action = webdriver.ActionChains(driver) action.click_and_hold(circle_button).perform() time.sleep(0.1) for track in track_list: y = random.uniform(-1, 1) action.move_by_offset(track, y) time.sleep(0.1) action.release(circle_button).perform() time.sleep(3) html = driver.page_source # print(len(html)) return len(html) def main(self): # path = "hua" path = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) path = "Images/" + path if not os.path.exists(path): os.makedirs(path) url = 'https://www.tianyancha.com/login' driver = webdriver.Chrome() driver.get(url) time.sleep(3) driver.find_element_by_xpath('//*[@id="web-content"]/div/div[2]/div/div/div[3]/div[3]/div[1]/div[2]').click() time.sleep(0.2) driver.find_element_by_xpath('//*[@id="mobile"]').send_keys(self.username) time.sleep(0.3) driver.find_element_by_xpath('//*[@id="password"]').send_keys(self.password) time.sleep(3) # 点击登录按钮 driver.find_element_by_xpath('//*[@id="web-content"]/div/div[2]/div/div/div[3]/div[3]/div[2]/div[4]').click() time.sleep(5) # 上一步点击按钮有概率会点击无效,需要加上试错操作,如果点击失败后,重新点击获取截图 try: # 验证码初始图片截图 verification_code = driver.find_element_by_xpath( '/html/body/div[10]/div[2]/div[2]/div[1]/div[2]/div[1]/a[1]/div[1]') verification_code.screenshot(path + '/r.png') time.sleep(3) except: driver.find_element_by_xpath( '//*[@id="web-content"]/div/div[2]/div/div/div[3]/div[3]/div[2]/div[4]').click() # 刷新验证码 time.sleep(5) # 验证码初始图片截图 verification_code = driver.find_element_by_xpath( '/html/body/div[10]/div[2]/div[2]/div[1]/div[2]/div[1]/a[1]/div[1]') verification_code.screenshot(path + '/r.png') time.sleep(3) # 定位拖动滑动的圆圈位置 circle_button = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[2]/div[2]') circle_button.click() time.sleep(3) # 验证码拼图图片再次截图 verification_code1 = driver.find_element_by_xpath( '/html/body/div[10]/div[2]/div[2]/div[1]/div[2]/div[1]/a[2]/div[1]') verification_code1.screenshot(path + '/r1.png') image1 = Image.open(path + '/r.png') image2 = Image.open(path + '/r1.png') # 循环五次模拟操作滑动滑块,给与一定的差异值(初始的验证码滑动) for i in [0, 10, -10]: html_len = self.slide_block(image1, image2, circle_button, driver, i) if html_len > 200000: break # 三次有问题说明验证码较难或者是被小怪兽吃了,方便起见刷新验证码 if html_len < 200000: for refresh in range(2): time.sleep(3) driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[1]/div[3]/a[1]').click() # 刷新验证码 time.sleep(3) verification_code = driver.find_element_by_xpath( '/html/body/div[10]/div[2]/div[2]/div[1]/div[2]/div[1]/a[1]/div[1]') verification_code.screenshot(path + '/r.png') time.sleep(3) # 定位拖动滑动的圆圈位置 circle_button = driver.find_element_by_xpath('/html/body/div[10]/div[2]/div[2]/div[2]/div[2]') circle_button.click() time.sleep(3) # 验证码拼图图片再次截图 verification_code1 = driver.find_element_by_xpath( '/html/body/div[10]/div[2]/div[2]/div[1]/div[2]/div[1]/a[2]/div[1]') verification_code1.screenshot(path + '/r1.png') image1 = Image.open(path + '/r.png') image2 = Image.open(path + '/r1.png') html_len = self.slide_block(image1, image2, circle_button, driver, 0) if html_len > 200000: break # print(html_len) #打印长度 if html_len > 200000: cookie_items = driver.get_cookies() # print(cookie_items) cookie_str = '' cookie_dict = {} # 组装cookie字符串 for item_cookie in cookie_items: cookie_dict[item_cookie["name"]] = item_cookie["value"] item_str = item_cookie["name"] + "=" + item_cookie["value"] + "; " cookie_str += item_str # print(item_cookie) # 打印出来看一下 # print('cookie_str:', cookie_str) else: # cookie_str = '' cookie_dict = {} driver.close() # return cookie_str return cookie_dict if __name__ == '__main__': count = 0 for i in range(100): print("开始第%s次"%str(i+1)) cookie_dict = TianYanChaCookies('15251711240', 'pq8330866').main() if len(cookie_dict)>0: count+=1 print("测试%s次"%str(i+1)) print("成功%s次"%count) print("成功率:%s"%str(count/(i+1)),"%") print(cookie_dict) # print(cookie_str) |
企查查模拟登陆代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """ Created on Thu Jul 30 11:04:15 2020 启用开发者模式和JS代码注入改变navigator.webdriver的属性值为false后,登录可以成功防止webdriver检测(存在不确定行) 测试加开发者模式和JS代码注入的情况下,暂时测试100%成功,成功获取到cookie,代码的稳定性还有待检验 @author: 强延飞 """ import json from selenium import webdriver import time import random import requests import numpy as np class QiChaChaCookies(): def __init__(self, username, password): self.username = username self.password = password def ease_out_quad(self, x): return 1 - (1 - x) * (1 - x) def ease_out_quart(self, x): return 1 - pow(1 - x, 4) def ease_out_expo(self, x): if x == 1: return 1 else: return 1 - pow(2, -10 * x) def get_tracks(self, distance, seconds, ease_func): """ 根据轨迹离散分布生成的数学 生成 # 参考文档 https://www.jianshu.com/p/3f968958af5a 成功率很高 90% 往上 :param distance: 缺口位置 :param seconds: 时间 :param ease_func: 生成函数 :return: 轨迹数组 """ distance += 20 tracks = [0] offsets = [0] for t in np.arange(0.0, seconds, 0.1): ease = ease_func offset = round(ease(t / seconds) * distance) tracks.append(offset - offsets[-1]) offsets.append(offset) tracks.extend([-3, -2, -3, -2, -2, -2, -2, -1, -0, -1, -1, -1]) # print(tracks) return tracks def main(self): url = 'https://www.qcc.com/user_login' # 登录地址 # url = 'https://login.taobao.com/member/login.jhtml' options = webdriver.ChromeOptions() options.add_experimental_option("excludeSwitches", ["enable-automation"]) # 设置开发者模式启动,该模式下webdriver属性为正常值 driver = webdriver.Chrome(options=options) # 使用带属性参数的谷歌浏览器 # driver = webdriver.Chrome() driver.get(url) # 进行请求 script = 'Object.defineProperty(navigator,"webdriver",{get:() => false,});' # 编写js脚本 driver.execute_script(script) # 执行js脚本 # 上面两行是防止网站监测到自动化测试软件 time.sleep(1.232) driver.find_element_by_xpath('//*[@id="normalLogin"]').click() # 找到正常的登录的元素,点击 time.sleep(1.0232) driver.find_element_by_xpath('//*[@id="nameNormal"]').send_keys(self.username) # 向账户框发送账户 time.sleep(1.8315) driver.find_element_by_xpath('//*[@id="pwdNormal"]').send_keys(self.password) # 向密码框发送密码 # 下面是验证码登录 # 滑动验证码 存在问题:滑动滑动距离distance需要确定 square_button = driver.find_element_by_xpath('//*[@id="nc_1_n1z"]') # 获得拖动滑块的按钮 distance = 370 # 370个px # track_list = get_track(distance) action = webdriver.ActionChains(driver) # 定义动作链 action.click_and_hold(square_button).perform() # 首先一直保持按住滑块按钮 # for track in track_list: track_list = self.get_tracks(distance, 5, self.ease_out_expo) for track in track_list: y = random.uniform(-1, 1) action.move_by_offset(track, y) # action.move_by_offset(distance, 0) # 向右移动一段距离,y坐标保持不变 action.release(square_button).perform() # 释放保持滑动按钮 time.sleep(5) # 点击登录按钮 driver.find_element_by_xpath('//*[@id="user_login_normal"]/button').click() time.sleep(5) # 获取cookie cookie_items = driver.get_cookies() cookie_str = '' cookie_dict = {} # 组装cookie字符串 for item_cookie in cookie_items: cookie_dict[item_cookie["name"]] = item_cookie["value"] item_str = item_cookie["name"] + "=" + item_cookie["value"] + "; " cookie_str += item_str # print(item_cookie) # 打印出来看一下 # print('cookies:', cookie_dict) driver.close() return cookie_dict def verify_cookie(self, cookies): url = 'https://www.qcc.com/company_getinfos?unique=d38fd1da97458b037750ff31ebd38d59&companyname=%E5%8D%97%E4%BA%AC%E4%B8%AD%E6%96%B0%E8%B5%9B%E5%85%8B%E7%A7%91%E6%8A%80%E6%9C%89%E9%99%90%E8%B4%A3%E4%BB%BB%E5%85%AC%E5%8F%B8&p=2&tab=assets&box=zhuanli&zlpublicationyear=&zlipclist=&zlkindcode=&zllegalstatus=' headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36' } r = requests.get(url, headers=headers, cookies=cookies, allow_redirects=False) print(r.status_code) # 不好使 html = r.text # 通过返回的字符个数进行验证即可 print(html) if __name__ == '__main__': cookie1 = QiChaChaCookies("15251711240", "pq8330866") cookie_dict = cookie1.main() print(json.dumps(cookie_dict)) print(cookie1.verify_cookie(cookie_dict)) |
检测模块¶
现在可以用生成模块来生成 Cookies,但还是免不了 Cookies 失效的问题,例如时间太长导致 Cookies 失效,或者 Cookies 使用太频繁导致无法正常请求网页。如果遇到这样的 Cookies,我们肯定不能让它继续保存在数据库里。
所以我们还需要增加一个定时检测模块,它负责遍历池中的所有 Cookies,同时设置好对应的检测链接,我们用一个个 Cookies 去请求这个链接。如果请求成功,或者状态码合法,那么该 Cookies 有效;如果请求失败,或者无法获取正常的数据,比如直接跳回登录页面或者跳到验证页面,那么此 Cookies 无效,我们需要将该 Cookies 从数据库中移除。
此 Cookies 移除之后,刚才所说的生成模块就会检测到 Cookies 的 Hash 和账号的 Hash 相比少了此账号的 Cookies,生成模块就会认为这个账号还没生成 Cookies,那么就会用此账号重新登录,此账号的 Cookies 又被重新更新。
检测模块需要做的就是检测 Cookies 失效,然后将其从数据中移除。
为了实现通用可扩展性,我们首先定义一个检测器的父类,声明一些通用组件,实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 | class ValidTester(object): def __init__(self, website='default'): self.website = website self.cookies_db = RedisClient('cookies', self.website) self.accounts_db = RedisClient('accounts', self.website) def test(self, username, cookies): # 子类重写 raise NotImplementedError def run(self): cookies_groups = self.cookies_db.all() # 获取cookies数据库的所有键值 for username, cookies in cookies_groups.items(): self.test(username, cookies) # 调用检测方法 |
在这里定义了一个父类叫作 ValidTester,在__init__() 方法里指定好站点的名称 website,
另外建立两个存储模块连接对象 cookies_db 和 accounts_db,分别负责操作 Cookies 和账号的 Hash,
run() 方法是入口,在这里是遍历了所有的 Cookies,然后调用 test() 方法进行测试,
在这里 test() 方法是没有实现的,也就是说我们需要写一个子类来重写这个 test() 方法,每个子类负责各自不同网站的检测,
如检测天眼查的就可以定义为 TianYanChaValidTester
,实现其独有的 test() 方法
来检测天眼查的 Cookies 是否合法,然后做相应的处理,
所以在这里我们还需要再加一个子类来继承这个 ValidTester,重写其 test() 方法,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | import json import requests from requests.exceptions import ConnectionError from cookiespool.db import * from cookiespool.config import * # 后期调度用 # 检测模块,用来检测cookies是否失效 class ValidTester(object): def __init__(self, website='default'): self.website = website self.cookies_db = RedisClient('cookies', self.website) self.accounts_db = RedisClient('accounts', self.website) def test(self, username, cookies): # 子类重写 raise NotImplementedError def run(self): cookies_groups = self.cookies_db.all() # 获取cookies数据库的所有键值 for username, cookies in cookies_groups.items(): self.test(username, cookies) # 调用检测方法 class TianYanChaValidTester(ValidTester): def __init__(self, website='tianyancha'): ValidTester.__init__(self, website) self.website = website def test(self, username, cookies): # 循环进行检测 print('正在测试%s_Cookies' % self.website, '用户名', username) try: cookies = json.loads(cookies) # 将前面转换成json的cookies字典重新转换一下 except TypeError: print('%s_Cookies不合法' % self.website, username) # 转换出错就是cookies有问题呗 self.cookies_db.delete(username) print('删除%s_Cookies' % self.website, username) return try: # 下面开始测试 test_url = TEST_URL_MAP[self.website] # 从config中获取该网站对应的测试网址 response = requests.get(test_url, cookies=cookies, timeout=5, allow_redirects=False) if response.status_code == 200: print('%s_Cookies有效' % self.website, username) else: print(response.status_code, response.headers) print('%s_Cookies失效' % self.website, username) self.cookies_db.delete(username) print('删除%s_Cookies' % self.website, username) except ConnectionError as e: print('发生异常', e.args) class QiChaChaValidTester(ValidTester): def __init__(self, website='qichacha'): ValidTester.__init__(self, website) self.website = website def test(self, username, cookies): # 循环进行检测 print('正在测试%s_Cookies' % self.website, '用户名', username) try: cookies = json.loads(cookies) # 将前面转换成json的cookies字典重新转换一下 # print(cookies) except TypeError: print('%s_Cookies不合法' % self.website, username) # 转换出错就是cookies有问题呗 self.cookies_db.delete(username) print('删除%s_Cookies' % self.website, username) return try: # 下面开始测试 test_url = TEST_URL_MAP[self.website] # 从config中获取该网站对应的测试网址 headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36', } response = requests.get(test_url, cookies=cookies, headers=headers, timeout=5, allow_redirects=False) if response.status_code == 200 and len(response.text) > 100: print('%s_Cookies有效' % self.website, username) else: print(response.status_code, response.headers, response.text) print('%s_Cookies失效' % self.website, username) # self.cookies_db.delete(username) print('删除%s_Cookies' % self.website, username) except ConnectionError as e: print('发生异常', e.args) if __name__ == '__main__': QiChaChaValidTester().run() |
test() 方法首先将 Cookies 转化为字典,检测 Cookies 的格式,如果格式不正确,直接将其删除,如果格式没问题,那么就拿此 Cookies 请求被检测的 URL。
test() 方法在这里检测天眼查,检测的 URL 可以是某个 Ajax 接口,为了实现可配置化,我们将测试 URL 也定义成字典,如下所示:
1 2 3 4 | TEST_URL_MAP = { 'tianyancha': 'https://www.tianyancha.com/relation', 'qichacha': 'https://www.qcc.com/company_getinfos?unique=d38fd1da97458b037750ff31ebd38d59&companyname=%E5%8D%97%E4%BA%AC%E4%B8%AD%E6%96%B0%E8%B5%9B%E5%85%8B%E7%A7%91%E6%8A%80%E6%9C%89%E9%99%90%E8%B4%A3%E4%BB%BB%E5%85%AC%E5%8F%B8&p=2&tab=assets&box=zhuanli&zlpublicationyear=&zlipclist=&zlkindcode=&zllegalstatus=' } |
如果要扩展其他站点,我们可以统一在字典里添加。对天眼查来说,我们用 Cookies 去请求目标站点,同时禁止重定向和设置超时时间,得到响应之后检测其返回状态码。如果直接返回 200 状态码,则 Cookies 有效,否则可能遇到了 302 跳转等情况,一般会跳转到登录页面,则 Cookies 已失效。如果 Cookies 失效,我们将其从 Cookies 的 Hash 里移除即可。
接口模块¶
生成模块和检测模块如果定时运行就可以完成 Cookies 实时检测和更新。但是 Cookies 最终还是需要给爬虫来用,同时一个 Cookies 池可供多个爬虫使用,所以我们还需要定义一个 Web 接口,爬虫访问此接口便可以取到随机的 Cookies。我们采用 Flask 来实现接口的搭建,代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | import json from flask import Flask, g from cookiespool.config import * from cookiespool.db import * __all__ = ['app'] app = Flask(__name__) @app.route('/') def index(): # 初始界面 return '<h2>Welcome to Cookie Pool System</h2>' def get_conn(): """ 获取 :return: """ for website in GENERATOR_MAP: #产生器类(可以多个) print(website) if not hasattr(g, website): setattr(g, website + '_cookies', eval('RedisClient' + '("cookies", "' + website + '")')) setattr(g, website + '_accounts', eval('RedisClient' + '("accounts", "' + website + '")')) return g @app.route('/<website>/random') def random(website): """ 获取随机的Cookie, 访问地址如 /weibo/random :return: 随机Cookie """ g = get_conn() cookies = getattr(g, website + '_cookies').random() return cookies @app.route('/<website>/add/<username>/<password>') def add(website, username, password): """ 添加用户, 访问地址如 /weibo/add/user/password :param website: 站点 :param username: 用户名 :param password: 密码 :return: """ g = get_conn() print(username, password) getattr(g, website + '_accounts').set(username, password) return json.dumps({'status': '1'}) @app.route('/<website>/count') def count(website): """ 获取Cookies总数 """ g = get_conn() count = getattr(g, website + '_cookies').count() return json.dumps({'status': '1', 'count': count}) if __name__ == '__main__': app.run(host='127.0.0.1') |
我们同样需要实现通用的配置来对接不同的站点,所以接口链接的第一个字段定义为站点名称,第二个字段定义为获取的方法,例如,/tianyancha/random 是获取天眼查的随机 Cookies,/qichacha/random 是获取企查查的随机 Cookies。
调度模块¶
最后,我们再加一个调度模块让这几个模块配合运行起来,主要的工作就是驱动几个模块定时运行,同时各个模块需要在不同进程上运行,实现如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import time from multiprocessing import Process from cookiespool.api import app from cookiespool.config import * from cookiespool.generator import * from cookiespool.tester import * class Scheduler(object): @staticmethod def valid_cookie(cycle=CYCLE): while True: print('Cookies检测进程开始运行') try: for website, cls in TESTER_MAP.items(): #Python 字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。 print('%s_Cookies检测进程开始运行' % website) tester = eval(cls + '(website="' + website + '")') #动态创建类对象(里面的字典是站点名对应的生成模块类) tester.run() print('%s_Cookies检测进程结束运行'%website) del tester #对象删除 time.sleep(cycle) except Exception as e: print(e.args) @staticmethod def generate_cookie(cycle=CYCLE): while True: print('Cookies生成进程开始运行') try: for website, cls in GENERATOR_MAP.items(): print('%s_Cookies生成进程开始运行' % website) generator = eval(cls + '(website="' + website + '")') generator.run() print('%s_Cookies生成进程结束运行'%website) # generator.close() #用不上是用来结束浏览器的 time.sleep(cycle) except Exception as e: print(e.args) @staticmethod def api(): #接口 print('API接口开始运行') app.run(host=API_HOST, port=API_PORT) # @staticmethod 静态方法只是名义上归属类管理,但是不能使用类变量和实例变量,是类的工具包 # 放在函数前(该函数不传入self或者cls),所以不能访问类属性和实例属性 def run(self): if API_PROCESS: #如果是True就开起api接口 api_process = Process(target=Scheduler.api) # api_process.start() if GENERATOR_PROCESS: #开启生成模块进程 generate_process = Process(target=Scheduler.generate_cookie) generate_process.start() if VALID_PROCESS: valid_process = Process(target=Scheduler.valid_cookie) valid_process.start() if __name__ == "__main__": s = Scheduler() s.run() |
这里用到了两个重要的配置,即产生模块类和测试模块类的字典配置,如下所示:
这样的配置是为了方便动态扩展使用的,键名为站点名称,键值为类名。如需要配置其他站点可以在字典中添加.
1 2 3 4 5 6 7 8 9 10 11 | # 产生器类,如扩展其他站点,请在此配置 GENERATOR_MAP = { 'tianyancha': 'TianYanChaCookiesGenerator', 'qichacha': 'QiChaChaCookiesGenerator' } # 测试类,如扩展其他站点,请在此配置 TESTER_MAP = { 'tianyancha': 'TianYanChaValidTester', 'qichacha': 'QiChaChaValidTester' } |
Scheduler 里将字典进行遍历,同时利用 eval() 动态新建各个类的对象,调用其入口 run() 方法运行各个模块。
同时,各个模块的多进程使用了 multiprocessing 中的 Process 类,调用其 start() 方法即可启动各个进程。
另外,各个模块还设有模块开关,我们可以在配置文件中自由设置开关的开启和关闭,如下所示:
1 2 3 4 5 6 | # 产生模块开关 GENERATOR_PROCESS = True # 验证模块开关 VALID_PROCESS = False # 接口模块开关 API_PROCESS = True |
定义为 True 即可开启该模块,定义为 False 即关闭此模块。
至此,我们的 Cookies 就全部完成了。接下来我们将模块同时开启,启动调度器,控制台类似输出如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 API接口开始运行 * Serving Flask app "cookiespool.api" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) Cookies生成进程开始运行 tianyancha_Cookies生成进程开始运行 tianyancha_Cookies检测进程结束运行 正在生成tianyancha_Cookies 账号 15251711240 密码 pq8330866 qichacha_Cookies检测进程开始运行 qichacha_Cookies检测进程结束运行 成功获取到tianyancha_Cookies {'tyc-user-phone': '%255B%252215251711240%2522%255D', 'auth_token': 'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTI1MTcxMTI0MCIsImlhdCI6MTYwMDIzNTY2NywiZXhwIjoxNjMxNzcxNjY3fQ.GJYACboAi6yPyXBR8YHC8lQwxFs6HhBSqqiKEOD_vLgabawRlftWVk44YgSUyLaM2YxnyPMSih3-Qvy2Mg-M5g', 'tyc-user-info': '{%22claimEditPoint%22:%220%22%2C%22vipToMonth%22:%22false%22%2C%22explainPoint%22:%220%22%2C%22personalClaimType%22:%22none%22%2C%22integrity%22:%2210%25%22%2C%22state%22:%220%22%2C%22score%22:%2229%22%2C%22announcementPoint%22:%220%22%2C%22messageShowRedPoint%22:%220%22%2C%22bidSubscribe%22:%22-1%22%2C%22vipManager%22:%220%22%2C%22onum%22:%220%22%2C%22monitorUnreadCount%22:%220%22%2C%22discussCommendCount%22:%220%22%2C%22showPost%22:null%2C%22messageBubbleCount%22:%220%22%2C%22claimPoint%22:%220%22%2C%22token%22:%22eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNTI1MTcxMTI0MCIsImlhdCI6MTYwMDIzNTY2NywiZXhwIjoxNjMxNzcxNjY3fQ.GJYACboAi6yPyXBR8YHC8lQwxFs6HhBSqqiKEOD_vLgabawRlftWVk44YgSUyLaM2YxnyPMSih3-Qvy2Mg-M5g%22%2C%22schoolAuthStatus%22:%222%22%2C%22userId%22:%22215645574%22%2C%22scoreUnit%22:%22%22%2C%22redPoint%22:%220%22%2C%22myTidings%22:%220%22%2C%22companyAuthStatus%22:%222%22%2C%22originalScore%22:%2229%22%2C%22myAnswerCount%22:%220%22%2C%22myQuestionCount%22:%220%22%2C%22signUp%22:%220%22%2C%22privateMessagePointWeb%22:%220%22%2C%22nickname%22:%22%E5%AE%8B%E7%8E%89%22%2C%22privateMessagePoint%22:%220%22%2C%22bossStatus%22:%222%22%2C%22isClaim%22:%220%22%2C%22yellowDiamondEndTime%22:%220%22%2C%22yellowDiamondStatus%22:%22-1%22%2C%22pleaseAnswerCount%22:%220%22%2C%22bizCardUnread%22:%220%22%2C%22vnum%22:%220%22%2C%22mobile%22:%2215251711240%22}', '_utm': '527bcd867c9b436b877d1ae7e1bd1071', 'token': '97158fb0b8724e8e8d06f7f4f14e48c3', '_gat_gtag_UA_123487620_1': '1', '_gid': 'GA1.2.1405745780.1600235679', 'Hm_lvt_e92c8d65d92d534b0fc290df538b4758': '1600235678', 'csrfToken': '41s2fNUu123UDmg5Fh8V8o3n', 'TYCID': '023d5e60f7e111eab7ea6fcdde9d7352', 'bannerFlag': 'false', 'aliyungf_tc': 'AQAAALrxxX3MIQgA/HVTKFdYdjbMffcG', '_ga': 'GA1.2.2042896897.1600235679', 'Hm_lpvt_e92c8d65d92d534b0fc290df538b4758': '1600235678', 'ssuid': '9680156877'} 成功保存tianyancha_Cookies 正在生成tianyancha_Cookies 账号 17824825277 密码 Hua@123123 Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 正在测试tianyancha_Cookies 用户名 15251711240 tianyancha_Cookies有效 15251711240 tianyancha_Cookies检测进程结束运行 qichacha_Cookies检测进程开始运行 qichacha_Cookies检测进程结束运行 Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 正在测试tianyancha_Cookies 用户名 15251711240 tianyancha_Cookies有效 15251711240 tianyancha_Cookies检测进程结束运行 成功获取到tianyancha_Cookies {'tyc-user-phone': '%255B%252217824825277%2522%255D', 'auth_token': 'eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNzgyNDgyNTI3NyIsImlhdCI6MTYwMDIzNTc1OSwiZXhwIjoxNjMxNzcxNzU5fQ.zmvPxQf-F3FvC7mIHjvlNpx35XhYWq6lGT5lQTr8yD9DjUgiWZWdeW1D95aYidxLHGMlOGD87slMqcUzz-Rfog', 'tyc-user-info': '{%22claimEditPoint%22:%220%22%2C%22vipToMonth%22:%22false%22%2C%22explainPoint%22:%220%22%2C%22personalClaimType%22:%22none%22%2C%22integrity%22:%2210%25%22%2C%22state%22:%220%22%2C%22score%22:%220%22%2C%22announcementPoint%22:%220%22%2C%22messageShowRedPoint%22:%220%22%2C%22bidSubscribe%22:%22-1%22%2C%22vipManager%22:%220%22%2C%22onum%22:%220%22%2C%22monitorUnreadCount%22:%220%22%2C%22discussCommendCount%22:%220%22%2C%22showPost%22:null%2C%22messageBubbleCount%22:%220%22%2C%22claimPoint%22:%220%22%2C%22token%22:%22eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxNzgyNDgyNTI3NyIsImlhdCI6MTYwMDIzNTc1OSwiZXhwIjoxNjMxNzcxNzU5fQ.zmvPxQf-F3FvC7mIHjvlNpx35XhYWq6lGT5lQTr8yD9DjUgiWZWdeW1D95aYidxLHGMlOGD87slMqcUzz-Rfog%22%2C%22schoolAuthStatus%22:%222%22%2C%22userId%22:%22220971292%22%2C%22scoreUnit%22:%22%22%2C%22redPoint%22:%220%22%2C%22myTidings%22:%220%22%2C%22companyAuthStatus%22:%222%22%2C%22originalScore%22:%220%22%2C%22myAnswerCount%22:%220%22%2C%22myQuestionCount%22:%220%22%2C%22signUp%22:%220%22%2C%22privateMessagePointWeb%22:%220%22%2C%22nickname%22:%22%E9%83%91%E6%A1%93%E5%85%AC%22%2C%22privateMessagePoint%22:%220%22%2C%22bossStatus%22:%222%22%2C%22isClaim%22:%220%22%2C%22yellowDiamondEndTime%22:%220%22%2C%22yellowDiamondStatus%22:%22-1%22%2C%22pleaseAnswerCount%22:%220%22%2C%22bizCardUnread%22:%220%22%2C%22vnum%22:%220%22%2C%22mobile%22:%2217824825277%22}', '_utm': 'eea988a9d80a4b22aaa611da2d302ce4', 'token': 'a7f1444be7084fe4ab90878420d27db6', '_gid': 'GA1.2.1752883369.1600235724', 'Hm_lvt_e92c8d65d92d534b0fc290df538b4758': '1600235723', 'csrfToken': 'oTteGXg0nPji3lDFi1UfXbow', 'TYCID': '1cf238c0f7e111eaaa7f59c93dcdbeba', 'bannerFlag': 'false', 'aliyungf_tc': 'AQAAAKzQ4kudKAUA/HVTKE4K/Qvb2WjX', '_ga': 'GA1.2.470793428.1600235724', 'Hm_lpvt_e92c8d65d92d534b0fc290df538b4758': '1600235723', 'ssuid': '8857380909'} 成功保存tianyancha_Cookies tianyancha_所有账号都已经成功获取Cookies tianyancha_Cookies生成进程结束运行 qichacha_Cookies检测进程开始运行 qichacha_Cookies检测进程结束运行 qichacha_Cookies生成进程开始运行 正在生成qichacha_Cookies 账号 15251711240 密码 pq8330866 Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 正在测试tianyancha_Cookies 用户名 17824825277 tianyancha_Cookies有效 17824825277 正在测试tianyancha_Cookies 用户名 15251711240 tianyancha_Cookies有效 15251711240 tianyancha_Cookies检测进程结束运行 成功获取到qichacha_Cookies {'zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f': '%7B%22sid%22%3A%201600235857412%2C%22updated%22%3A%201600235877453%2C%22info%22%3A%201600235857419%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%22b5109d19364a4ccfe887cd6279637a79%22%7D', 'hasShow': '1', 'Hm_lpvt_78f134d5a9ac3f92524914d0247e70cb': '1600235876', 'zg_did': '%7B%22did%22%3A%20%22174957d65ff5c7-00a1fb2350fadb-333769-15f900-174957d6600a9%22%7D', 'QCCSESSID': 'fnkmuqd65juaiq8m7uufe3fis7', 'CNZZDATA1254842228': '299503459-1600234173-%7C1600234173', '_uab_collina': '160023585206261917340225', 'UM_distinctid': '174957d529b6b4-0b84b350038d07-333769-15f900-174957d529c705', 'Hm_lvt_78f134d5a9ac3f92524914d0247e70cb': '1600235856', 'acw_tc': 'a3b5219716002358117835851ed983e9f1ac70bb232126be179a15717c'} 成功保存qichacha_Cookies 正在生成qichacha_Cookies 账号 17824825277 密码 Hua@123123 qichacha_Cookies检测进程开始运行 正在测试qichacha_Cookies 用户名 15251711240 qichacha_Cookies有效 15251711240 qichacha_Cookies检测进程结束运行 Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 正在测试tianyancha_Cookies 用户名 17824825277 成功获取到qichacha_Cookies {'zg_de1d1a35bfa24ce29bbf2c7eb17e6c4f': '%7B%22sid%22%3A%201600235898018%2C%22updated%22%3A%201600235920654%2C%22info%22%3A%201600235898021%2C%22superProperty%22%3A%20%22%7B%7D%22%2C%22platform%22%3A%20%22%7B%7D%22%2C%22utm%22%3A%20%22%7B%7D%22%2C%22referrerDomain%22%3A%20%22%22%2C%22cuid%22%3A%20%2261785dc2271156fd5b61cb8e8b04cede%22%7D', 'hasShow': '1', '_uab_collina': '160023589773311989102072', 'CNZZDATA1254842228': '595383533-1600234173-%7C1600234173', 'QCCSESSID': '9rdbva06s710eu6lafmbp3dg63', 'UM_distinctid': '174957e04ea701-0310aaa697eb4d-333769-15f900-174957e04eb9d', 'Hm_lpvt_78f134d5a9ac3f92524914d0247e70cb': '1600235921', 'zg_did': '%7B%22did%22%3A%20%22174957e049d582-09aba916fd4f93-333769-15f900-174957e049e679%22%7D', 'Hm_lvt_78f134d5a9ac3f92524914d0247e70cb': '1600235899', 'acw_tc': 'a3b5219616002358553913747e5e08f944621ee29cac4b5353647db690'} 成功保存qichacha_Cookies qichacha_所有账号都已经成功获取Cookies qichacha_Cookies生成进程结束运行 tianyancha_Cookies有效 17824825277 正在测试tianyancha_Cookies 用户名 15251711240 tianyancha_Cookies有效 15251711240 tianyancha_Cookies检测进程结束运行 Cookies生成进程开始运行 tianyancha_Cookies生成进程开始运行 qichacha_Cookies检测进程开始运行 正在测试qichacha_Cookies 用户名 17824825277 tianyancha_所有账号都已经成功获取Cookies tianyancha_Cookies生成进程结束运行 qichacha_Cookies有效 17824825277 正在测试qichacha_Cookies 用户名 15251711240 qichacha_Cookies有效 15251711240 qichacha_Cookies检测进程结束运行 tianyancha qichacha 127.0.0.1 - - [16/Sep/2020 13:59:31] "GET /qichacha/random HTTP/1.1" 200 - 127.0.0.1 - - [16/Sep/2020 13:59:31] "GET /favicon.ico HTTP/1.1" 404 - qichacha_Cookies生成进程开始运行 Cookies检测进程开始运行 tianyancha_Cookies检测进程开始运行 正在测试tianyancha_Cookies 用户名 17824825277 qichacha_所有账号都已经成功获取Cookies qichacha_Cookies生成进程结束运行 tianyancha_Cookies有效 17824825277 正在测试tianyancha_Cookies 用户名 15251711240 tianyancha_Cookies有效 15251711240 tianyancha_Cookies检测进程结束运行 Cookies生成进程开始运行 tianyancha_Cookies生成进程开始运行 qichacha_Cookies检测进程开始运行 正在测试qichacha_Cookies 用户名 17824825277 qichacha_Cookies有效 17824825277 正在测试qichacha_Cookies 用户名 15251711240 tianyancha_所有账号都已经成功获取Cookies tianyancha_Cookies生成进程结束运行 qichacha_Cookies有效 15251711240 qichacha_Cookies检测进程结束运行 |
以上所示是程序运行的控制台输出内容,我们从中可以看到各个模块都正常启动,测试模块逐个测试 Cookies,生成模块获取尚未生成 Cookies 的账号的 Cookies,各个模块并行运行,互不干扰。
我们可以访问接口获取随机的 Cookies,如图 10-13 所示。
图 10-13 接口页面
爬虫只需要请求该接口就可以实现随机 Cookies 的获取。
5. 本节代码¶
本节代码地址:https://github.com/Python3WebSpider/CookiesPool。
6. 结语¶
以上内容便是 Cookies 池的用法,后文中我们会利用该 Cookies 池和之前所讲的代理池来进行新浪微博的大规模爬取。都已